From 96589b359fd7212765dd532c5ee693cbd1fbfefb Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 10 Jan 2015 23:03:58 -0800 Subject: [PATCH] Print nicer messages on 'no package named' errors The new message will print out a selection of versions that were found if any are to be had, as well as a recommendation to run `cargo update` if it's a path dependency. Closes #1145 --- src/cargo/core/resolver/mod.rs | 41 +++++++++++++++++++++++++++-- tests/resolve.rs | 2 +- tests/test_cargo_compile.rs | 41 ++++++++++++++++++++++++++++- tests/test_cargo_registry.rs | 47 ++++++++++++++++++++++++++++++---- 4 files changed, 122 insertions(+), 9 deletions(-) diff --git a/src/cargo/core/resolver/mod.rs b/src/cargo/core/resolver/mod.rs index 066dac76f..11a4d0ca4 100644 --- a/src/cargo/core/resolver/mod.rs +++ b/src/cargo/core/resolver/mod.rs @@ -326,12 +326,49 @@ fn activate_deps<'a, R: Registry>(cx: Context, Err(human(msg)) } None => { - Err(human(format!("no package named `{}` found (required by `{}`)\n\ + // Once we're all the way down here, we're definitely lost in the + // weeds! We didn't actually use any candidates above, so we need to + // give an error message that nothing was found. + // + // Note that we re-query the registry with a new dependency that + // allows any version so we can give some nicer error reporting + // which indicates a few versions that were actually found. + let msg = format!("no matching package named `{}` found \ + (required by `{}`)\n\ location searched: {}\n\ version required: {}", dep.get_name(), parent.get_name(), dep.get_source_id(), - dep.get_version_req()))) + dep.get_version_req()); + let mut msg = msg; + let all_req = semver::VersionReq::parse("*").unwrap(); + let new_dep = dep.clone().version_req(all_req); + let mut candidates = try!(registry.query(&new_dep)); + candidates.sort_by(|a, b| { + b.get_version().cmp(a.get_version()) + }); + if candidates.len() > 0 { + msg.push_str("\nversions found: "); + for (i, c) in candidates.iter().take(3).enumerate() { + if i != 0 { msg.push_str(", "); } + msg.push_str(c.get_version().to_string().as_slice()); + } + if candidates.len() > 3 { + msg.push_str(", ..."); + } + } + + // If we have a path dependency with a locked version, then this may + // indicate that we updated a sub-package and forgot to run `cargo + // update`. In this case try to print a helpful error! + if dep.get_source_id().is_path() && + dep.get_version_req().to_string().starts_with("=") && + candidates.len() > 0 { + msg.push_str("\nconsider running `cargo update` to update \ + a path dependency's locked version"); + + } + Err(human(msg)) } }) } diff --git a/tests/resolve.rs b/tests/resolve.rs index 92d24ed6a..9dcd97219 100644 --- a/tests/resolve.rs +++ b/tests/resolve.rs @@ -335,7 +335,7 @@ fn resolving_but_no_exists() { assert!(res.is_err()); assert_eq!(res.unwrap_err().to_string(), "\ -no package named `foo` found (required by `root`) +no matching package named `foo` found (required by `root`) location searched: registry http://example.com/ version required: ^1\ "); diff --git a/tests/test_cargo_compile.rs b/tests/test_cargo_compile.rs index 4dbea7017..fb81b74a8 100644 --- a/tests/test_cargo_compile.rs +++ b/tests/test_cargo_compile.rs @@ -513,12 +513,51 @@ test!(cargo_compile_with_dep_name_mismatch { assert_that(p.cargo_process("build"), execs().with_status(101).with_stderr(format!( -r#"no package named `notquitebar` found (required by `foo`) +r#"no matching package named `notquitebar` found (required by `foo`) location searched: {proj_dir} version required: * "#, proj_dir = p.url()))); }); +test!(compile_path_dep_then_change_version { + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [dependencies.bar] + path = "bar" + "#) + .file("src/lib.rs", "") + .file("bar/Cargo.toml", r#" + [package] + name = "bar" + version = "0.0.1" + authors = [] + "#) + .file("bar/src/lib.rs", ""); + + assert_that(p.cargo_process("build"), execs().with_status(0)); + + File::create(&p.root().join("bar/Cargo.toml")).unwrap().write_str(r#" + [package] + name = "bar" + version = "0.0.2" + authors = [] + "#).unwrap(); + + assert_that(p.process(cargo_dir().join("cargo")).arg("build"), + execs().with_status(101).with_stderr("\ +no matching package named `bar` found (required by `foo`) +location searched: [..] +version required: = 0.0.1 +versions found: 0.0.2 +consider running `cargo update` to update a path dependency's locked version +")); +}); + // test!(compiling_project_with_invalid_manifest) test!(crate_version_env_vars { diff --git a/tests/test_cargo_registry.rs b/tests/test_cargo_registry.rs index 770371d2e..2873d2ee3 100644 --- a/tests/test_cargo_registry.rs +++ b/tests/test_cargo_registry.rs @@ -100,12 +100,48 @@ test!(nonexistent { assert_that(p.cargo_process("build"), execs().with_status(101).with_stderr("\ -no package named `nonexistent` found (required by `foo`) +no matching package named `nonexistent` found (required by `foo`) location searched: registry file://[..] version required: >= 0.0.0 ")); }); +test!(wrong_version { + let p = project("foo") + .file("Cargo.toml", r#" + [project] + name = "foo" + version = "0.0.1" + authors = [] + + [dependencies] + foo = ">= 1.0.0" + "#) + .file("src/main.rs", "fn main() {}"); + + r::mock_pkg("foo", "0.0.1", &[]); + r::mock_pkg("foo", "0.0.2", &[]); + + assert_that(p.cargo_process("build"), + execs().with_status(101).with_stderr("\ +no matching package named `foo` found (required by `foo`) +location searched: registry file://[..] +version required: >= 1.0.0 +versions found: 0.0.2, 0.0.1 +")); + + r::mock_pkg("foo", "0.0.3", &[]); + r::mock_pkg("foo", "0.0.4", &[]); + + assert_that(p.cargo_process("build"), + execs().with_status(101).with_stderr("\ +no matching package named `foo` found (required by `foo`) +location searched: registry file://[..] +version required: >= 1.0.0 +versions found: 0.0.4, 0.0.3, 0.0.2, ... +")); +}); + test!(bad_cksum { let p = project("foo") .file("Cargo.toml", r#" @@ -149,7 +185,7 @@ test!(update_registry { assert_that(p.cargo_process("build"), execs().with_status(101).with_stderr("\ -no package named `notyet` found (required by `foo`) +no matching package named `notyet` found (required by `foo`) location searched: registry file://[..] version required: >= 0.0.0 ")); @@ -200,7 +236,7 @@ test!(package_with_path_deps { failed to verify package tarball Caused by: - no package named `notyet` found (required by `foo`) + no matching package named `notyet` found (required by `foo`) location searched: registry file://[..] version required: ^0.0.1 ")); @@ -344,9 +380,10 @@ test!(relying_on_a_yank_is_bad { assert_that(p.process(cargo_dir().join("cargo")).arg("build"), execs().with_status(101).with_stderr("\ -no package named `baz` found (required by `bar`) +no matching package named `baz` found (required by `bar`) location searched: registry file://[..] version required: = 0.0.2 +versions found: 0.0.1 ")); }); @@ -378,7 +415,7 @@ test!(yanks_in_lockfiles_are_ok { assert_that(p.process(cargo_dir().join("cargo")).arg("update"), execs().with_status(101).with_stderr("\ -no package named `bar` found (required by `foo`) +no matching package named `bar` found (required by `foo`) location searched: registry file://[..] version required: * ")); -- 2.30.2